<?

function t2s($str) {
  include_once(ROOT . '/include/TSConvert.php');
  return TSConvert::t2s($str);
}

function str_strip($string, $maxLength) {
  return (mb_strlen($string) > $maxLength + 10 ? mb_substr($string, 0, $maxLength - 1) . '..' : $string);
}

function object_map($arrayOfObjects, $key) {
	return array_map(function($o) use ($key) {return $o->$key;}, $arrayOfObjects);
}

function arr_map($arrayOfArrays, $key) {
	return array_map(function($o) use ($key) {return $o[$key];}, $arrayOfArrays);
}

function code_map() {
  return Config::get('env.code_map');
}

function hash_map($offset = 0) {
  $map = Config::get('env.hash_map');
  if ($offset) {
    $map = substr($map, $offset) . substr($map, 0, $offset);
  }
  return $map;
}

function month($time) {
  $map = [1 => '一月', 2 => '二月', 3 => '三月',
    4 => '四月', 5 => '五月', 6 => '六月',
    7 => '七月', 8 => '八月', 9 => '九月',
    10 => '十月', 11 => '十一月', 12 => '十二月'];
  return $map[date('n', $time)];
}

function weekdayMap($weekday) {
  $map = [1 => '周一', 2 => '周二', 3 => '周三', 4 => '周四', 5 => '周五', 6 => '周六', 7 => '周日'];
  return $map[$weekday];
}

function weekday($time) {
  return weekdayMap(date('N', $time));
}

function st($time) {
  if (date('Y-m-d', time()) == date('Y-m-d', $time)) {
    return date('H:i', $time);
  } else if (date('Y', time()) == date('Y', $time)) {
    return date('n.j H:i', $time);
  }

  return date('Y.n.j', $time);
}

function t($time) {
  $diff = time() - $time;
  if ($diff < 3600) {
    return intval($diff / 60 + 1) . '分钟前';
  } else if (time() - $time < 86400) {
    return intval($diff / 3600) . '小时前';
  }

  if (date('Y', time()) == date('Y', $time)) {
    return date('n月j日', $time);
  } else {
    return date('Y年n月j日', $time);
  }
}

function dt($mtime_start, $mtime_end) {
  list($ms_1, $s_1) = explode(' ', $mtime_start);
  list($ms_2, $s_2) = explode(' ', $mtime_end);

  return ($s_2 - $s_1) + ($ms_2 - $ms_1);
}

function isSpider() {
  return preg_match("/bot|spider|crawler|Mediapartners-Google/i", ua());
}

function ua() {
  return (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
}

function code2dec($code) {
  return base_convert(code2hex($code), 16, 10);
}

function dec2code($dec) {
  return hex2code(base_convert($dec, 10, 16));
}

function code2hex($code) {
  $map = code_map();

  $hex = '';
  while (strlen($code) > 0) {
    $sub_str = substr($code, -4);

    $ord = '';
    for ($i = 0; $i < 4; $i++) {
      if (strlen($sub_str)) {
        $char = substr($sub_str, -1);
        $sub_str = substr($sub_str, 0, -1);
        $ord = str_pad(base_convert(strpos($map, $char), 10, 2), 5, "0", STR_PAD_LEFT) . $ord;
      } else {
        $ord = '00000' . $ord;
      }
    }

    $hex = base_convert(substr($ord, 0, 4), 2, 16)
      . base_convert(substr($ord, 4, 4), 2, 16)
      . base_convert(substr($ord, 8, 4), 2, 16)
      . base_convert(substr($ord, 12, 4), 2, 16)
      . base_convert(substr($ord, 16, 4), 2, 16)
      . $hex;
    $code = substr($code, 0, strlen($code) - strlen($sub_str));
  }

  return ltrim($hex, '0');
}

function hex2code($hex) {
  $map = code_map();

  $code = '';
  while (strlen($hex) > 0) {
    $sub_str = substr($hex, -5);
    $ord = str_pad(base_convert($sub_str, 16, 2), 20, "0", STR_PAD_LEFT);
    $code = substr($map, base_convert(substr($ord, 0, 5), 2, 10), 1)
      . substr($map, base_convert(substr($ord, 5, 5), 2, 10), 1)
      . substr($map, base_convert(substr($ord, 10, 5), 2, 10), 1)
      . substr($map, base_convert(substr($ord, 15, 5), 2, 10), 1) . $code;
    $hex = substr($hex, 0, strlen($hex) - strlen($sub_str));
  }

  return $code;
}

/*
 * User: 2
 * Position: 3
 * Fake: 9
 */

function hash2dec($hash, $offset = 0) {
  return base_convert(hash2hex($hash, $offset), 16, 10);
}

function dec2hash($dec, $offset = 0) {
  return hex2hash(base_convert($dec, 10, 16), $offset);
}

function hash2hex($hash, $offset = 0) {
  $map = hash_map($offset);

  $hex = '';
  while (strlen($hash) > 0) {
    $sub_str = substr($hash, -2);
    $sub_str0 = $sub_str1 = '';
    if (strlen($sub_str) == 2) {
      $sub_str0 = substr($sub_str, 0, 1);
      $sub_str1 = substr($sub_str, 1, 1);
    } else {
      $sub_str1 = $sub_str;
    }

    $ord = str_pad(base_convert(strpos($map, $sub_str0), 10, 2), 6, "0", STR_PAD_LEFT)
         . str_pad(base_convert(strpos($map, $sub_str1), 10, 2), 6, "0", STR_PAD_LEFT);

    $hex = base_convert(substr($ord, 0, 4), 2, 16)
        . base_convert(substr($ord, 4, 4), 2, 16)
        . base_convert(substr($ord, 8, 4), 2, 16)
        . $hex;
    $hash = substr($hash, 0, strlen($hash) - strlen($sub_str));
  }

  return ltrim($hex, '0');
}

function hex2hash($hex, $offset = 0) {
  $map = hash_map($offset);

  $hash = '';
  while (strlen($hex) > 0) {
    $sub_str = substr($hex, -3);
    $ord = str_pad(base_convert($sub_str, 16, 2), 12, "0", STR_PAD_LEFT);
    $hash = substr($map, base_convert(substr($ord, 0, 6), 2, 10), 1)
        . substr($map, base_convert(substr($ord, 6, 6), 2, 10), 1) . $hash;
    $hex = substr($hex, 0, strlen($hex) - strlen($sub_str));
  }

  return $hash;
}

function utime($offset = 0) {
  list($m, $t) = explode(' ', microtime());
  return strval($t + $offset) .
      str_pad($m * 1000000, 6, "0", STR_PAD_LEFT) .
      str_pad(rand(0, 999), 3, "0", STR_PAD_LEFT);
}

function dump_all() {
	echo '<pre>';
	foreach (func_get_args() as $o) {
		print_r($o);
		echo "\n\n";
	}
	echo '</pre>';
}

function debug_info($message, $back = 0) {
	$info = array(
		'backtrace' => array_slice(debug_backtrace(0), $back + 1),
		'customMessage' => $message,
		'time' => date('Y-m-d H:i:s'),
		'url' => full_url(),
	);

	if (!IS_CLI) {
		$info = array(
			'get' => $_GET,
			'post' => $_POST,
			'cookie' => $_COOKIE,
			'ip' => remote_ip(),
			'ua' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
		) + $info;
	}
	return $info;
}

function backtrace_html($backtraces) {
	$html = '<table border="1">';
	foreach ($backtraces as $k => $backtrace) {
		$backtrace += array('class' => '', 'type' => '', 'line' => '', 'function' => '', 'file' => '');
		$type = isset($backtrace['type']) ? $backtrace['type'] : '';
		$type = str_replace(array('dynamic', 'static'), array('->', '::'), $type);
		$html .= "<tr><td>#{$k} {$backtrace['class']}{$type}{$backtrace['function']}()</td>";
		$html .= "<td>{$backtrace['file']}:{$backtrace['line']}</td></tr>";
	}
	$html .= '</table>';
	return $html;
}

function debug_info_html($message) {
	$info = debug_info($message);

	$html = "<h3>{$info['customMessage']}</h3>";
	unset($info['customMessage'], $info['backtrace']);
	array_walk($info, function($value, $key) use (&$html) {
		$str = '';
		if (is_array($value)) {
			$str .= "<p><b>$key</b>: </p>";
			if ($value) {
				$str .= "<table border='1'><tr><th>Key</th><th>Value</th></tr>";
				foreach ($value as $k => $v) {
					if (is_array($v)) $v = "(*)" . serialize($v);
					$str .= "<tr><td>" . htmlentities($k, 0, 'UTF-8') . "</td><td>"
						. htmlentities($v, 0, 'UTF-8') . "</td></tr>";
				}
				$str .= "</table>";
			}
		} else {
			$str .= "<p><b>$key</b>: ";
			$str .= htmlentities($value, 0, 'UTF-8') . "</p>";
		}
		$html .= $str;
	});
	return $html;
}

function get_called_function() {
	$_ = array_slice(xdebug_get_function_stack(), -3, 1);
	return $_[0]['function'];
}

function full_url() {
	if (IS_CLI) {
		return __FILE__ . " " . serialize($_SERVER['argv']);
	} else {
		$url = isset($_SERVER['SCRIPT_URI']) ? $_SERVER['SCRIPT_URI'] : $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
		return $url . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
	}
}

function remote_ip() {
	if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];	//Direct IP
	} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
		$ip = $_SERVER['HTTP_CLIENT_IP'];
	} elseif (isset($_SERVER['REMOTE_ADDR'])) {
		$ip = $_SERVER['REMOTE_ADDR'];
	} else {
		$ip = "127.0.0.1";	//for CLI
	}
	$ip_segment = explode(',', $ip);
	return $ip_segment[0];
}

function v($version = null) {
  if (!$version)
    $version = (isset($_POST['_version']) ? $_POST['_version'] :
        (isset($_GET['_version']) ? $_GET['_version'] : '100.0.0'));
  return ApiConfig::verValue($version);
}

function timetostr($time = NULL) {
	if (is_null($time)) {
		$time = time();
	}
	return date("Y-m-d H:i:s", intval($time));	//DateTime::RFC3339: "Y-m-d\TH:i:sP"
}

define('UTF8_ERR_BREAK', 0x01); //返回第一个非UTF8字符之前的字符串
define('UTF8_ERR_EXCEPTION', 0x02); //出现非UTF8字符时，抛出Exception
define('UTF8_ERR_FILTER', 0x04); //返回过滤掉非UTF8字符之后的字符串

define('UTF8_FILTER_DECODE', 0x10); //返回过滤掉非UTF8字符之后的字符串

function utf8_filter($string, $mode = UTF8_ERR_FILTER) {
	//这个正则还是漏掉了一部分非法的四字节UTF8字符，但是几乎很难遇到了
	$preg_str = '#([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|[\xE1-\xEF][\x80-\xBF]{2}|[\xF0-\xF4][\x81-\xBF][\x80-\xBF]{2})+#';
	if ($mode & UTF8_FILTER_DECODE) $string = urldecode($string);
	if (preg_match($preg_str, $string, $match)) {
		if ($match[0] != $string) { // 不完全符合
			if ($mode & UTF8_ERR_BREAK) { //在第一个非UTF-8字符的地方截断
				$string = $match[0];
			} elseif ($mode & UTF8_ERR_FILTER) {
				preg_match_all($preg_str, $string, $match);
				$string = join('', $match[0]);
			} elseif ($mode & UTF8_ERR_EXCEPTION) {
				throw new Exception('None UTF-8 string.');
			}
		}
	} else { // 完全不符合
		$string = '';
	};
	//还没有return 说明 没有任何一个UTF8 字符 或者出了错误，而且是 UTF8_ERR_EXCEPTION
	return $string;
}

function normalizeContact($number) {
  $dict = array(
    '0' => array("〇", "０", "零"),
    '1' => array("１", "壹", "①", "⑴", "⒈", "|", "㈠"),
    '2' => array("二", "２", "贰", "②", "⑵", "⒉", "㈡"),
    '3' => array("三", "３", "叁", "③", "⑶", "⒊", "㈢", "З"),
    '4' => array("四", "４", "肆", "④", "⑷", "⒋", "㈣"),
    '5' => array("五", "５", "伍", "⑤", "⑸", "⒌", "㈤"),
    '6' => array("六", "６", "陆", "⑥", "⑹", "⒍", "㈥"),
    '7' => array("七", "７", "柒", "⑦", "⑺", "⒎", "㈦"),
    '8' => array("八", "８", "捌", "⑧", "⑻", "⒏", "㈧"),
    '9' => array("九", "９", "玖", "⑨", "⑼", "⒐", "㈨"),
    'q' => array("ｑ", "Ｑ", "Q", "扣"),
    '@' => array("＠"),
    ' ' => array("　", "-", "－", "一", "_", "/", ".", "▃", "≡", "☎", ',', "'", ';', '；', '，'),
  );

  foreach ($dict as $k => $v) {
    $number = str_replace($v, $k, $number);
  }

  $number = str_replace(' ', '', $number);

  return $number;
}

function tokenOfString($string) {
  $host = Config::get("env.searcher.default");
  $tokens = [];
  $json = HttpClient::get($host . 'matcha/_analyze?analyzer=ik&text=' . urlencode($string));
  $res = json_decode($json, true);
  if (!is_array($res) || !isset($res['tokens']) || !is_array($res['tokens']) || !count($res['tokens'])) return [];
  foreach ($res['tokens'] as $t) {
    $token = trim($t['token']);
    if (!$token) continue;
    $tokens[$token] = $token;
  }
  return array_values($tokens);
}

function simpleEncode($string = '', $skey = 'mudlab9') {
  $strArr = str_split(base64_encode($string));
  $strCount = count($strArr);
  foreach (str_split($skey) as $key => $value)
    $key < $strCount && $strArr[$key].=$value;
  return str_replace(array('=', '+', '/'), array('O0O0O', 'o000o', 'oo00o'), join('', $strArr));
}

function simpleDecode($string = '', $skey = 'mudlab9') {
  try {
    $strArr = str_split(str_replace(array('O0O0O', 'o000o', 'oo00o'), array('=', '+', '/'), $string), 2);
    $strCount = count($strArr);
    foreach (str_split($skey) as $key => $value)
      $key <= $strCount && $strArr[$key][1] === $value && $strArr[$key] = $strArr[$key][0];
    return base64_decode(join('', $strArr));
  } catch(Exception $e) {
    return '';
  }
}

function isOnABTest($userId, $testKey) {
  $seed = $userId . $testKey;
  return intval(hexdec(substr(md5($seed), -1)) % 2);
}

function iconvstr($str){
  return iconv('utf-8','gb2312',$str);
}

function object_array_diff($array_1, $array_2) {
  foreach ($array_1 as $key => $item) {
    if (isset($array_2[$key])) {
      unset($array_1[$key]);
    }
  }
  return $array_1;
}